package com.hitqz.robot.biz.schedule;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.cache.Cache;
import com.hitqz.robot.api.business.enums.WorkStatusEnum;
import com.hitqz.robot.api.common.dto.info.RobotNavInfoDto;
import com.hitqz.robot.api.common.entity.BatteryDataInfo;
import com.hitqz.robot.api.common.entity.Robot;
import com.hitqz.robot.api.common.entity.RobotMapPos;
import com.hitqz.robot.api.dispatch.protocol.ProtocolEnum;
import com.hitqz.robot.api.dispatch.protocol.dto.CurrentTaskInfoDto;
import com.hitqz.robot.biz.service.BatteryDataInfoService;
import com.hitqz.robot.biz.service.RobotMapPosService;
import com.hitqz.robot.biz.service.RobotService;
import com.hitqz.robot.biz.service.impl.TicketsServiceIml;
import com.hitqz.robot.driver.model.IRobotPosDto;
import com.hitqz.robot.driver.parent.RobotDriverService;
import com.hitqz.robot.netty.service.Send2ServerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.operation.distance.DistanceOp;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author xupkun
 * @date 2024/11/15
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class StatisticalSchedule implements SmartInitializingSingleton {

    private final RobotDriverService robotDriverService;

    private final BatteryDataInfoService batteryDataInfoService;

    private final Send2ServerService send2ServerService;
    private final RobotService robotService;

    private final RobotMapPosService robotMapPosService;

    private List<RobotMapPos> allMapPos = new ArrayList<>();

    @Override
    public void afterSingletonsInstantiated() {
        Robot robot = robotService.getDefaultRobot();
        allMapPos = robotMapPosService.list(Wrappers.<RobotMapPos>lambdaQuery().eq(RobotMapPos::getMapCode, robot.getMapCode()));
    }

    /**
     * 电池数据统计
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void staticBattery() {
        IRobotPosDto iRobotPosDto = robotDriverService.getWebPos();
        if (iRobotPosDto != null) {
            BatteryDataInfo info = new BatteryDataInfo();
            if (iRobotPosDto.getCurrent() != null) {
                info.setBattery(String.format("%.2f", iRobotPosDto.getBatteryLevel()));
                info.setVoltage(String.format("%.2f", iRobotPosDto.getVoltage()));
                info.setCurrent(String.format("%.2f", Math.abs(Double.parseDouble(iRobotPosDto.getCurrent()))));
                batteryDataInfoService.save(info);
                send2ServerService.uploadBatteryLevel(robotService.getDefaultRobot().getRobotSn(), info);
            }
        } else {
            log.info("数据为空");
        }
    }


    /**
     * 机器人导航信息上报：上报机器人当前所在站点和实时行走路径
     */
    @Scheduled(fixedRate = 100L)
    public void reportRobotNavInfo() {
        try {
            IRobotPosDto iRobotPosDto = robotDriverService.getWebPos();
            Cache<String, CurrentTaskInfoDto> currentTaskInfo = SpringUtil.getBean("currentTaskInfo");
            if (iRobotPosDto != null) {
                Robot robot = robotService.getDefaultRobot();
                Cache<String, RobotMapPos> navTarget = SpringUtil.getBean("navTarget");

                RobotMapPos currentPos = findNearestPosition(iRobotPosDto, allMapPos);
                RobotNavInfoDto robotNavInfoDto = new RobotNavInfoDto();
                robotNavInfoDto.setRobotSn(robot.getRobotSn());

                CurrentTaskInfoDto taskInfoDto = currentTaskInfo.getIfPresent(robot.getRobotSn());
                if (taskInfoDto != null) {
                    robotNavInfoDto.setTaskNo(taskInfoDto.getTaskNo());
                    robotNavInfoDto.setTaskParams(taskInfoDto.getTaskParams());
                }
                robotNavInfoDto.setNavTaskStatus(iRobotPosDto.getTaskStatus());
                robotNavInfoDto.setWorkStatus(robot.getWorkStatus());
                robotNavInfoDto.setCurrentPos(currentPos);

                RobotMapPos targetPos = navTarget.getIfPresent(robot.getRobotSn());
                robotNavInfoDto.setTargetPos(targetPos);

                robotNavInfoDto.setMapPosList(allMapPos);

                robotNavInfoDto.setIsFull(iRobotPosDto.getFull());
                send2ServerService.send2ServerData(Integer.valueOf(ProtocolEnum.ROBOT_NAV_INFO_CMD.getCmd()),
                        JSONObject.toJSONString(robotNavInfoDto));
            } else {
                log.info("机器人状态数据为空");
            }
        } catch (Exception e) {
            log.error("机器人导航信息上报失败：{}", e.getMessage());
        }
    }

    private RobotMapPos findNearestPosition(IRobotPosDto posDto, List<RobotMapPos> mapPositions) {
        return this.nearPos(posDto.getX(), posDto.getY(), mapPositions);
    }

    private RobotMapPos nearPos(float x, float y, List<RobotMapPos> robotMapPosList) throws IllegalStateException {
        if (robotMapPosList.isEmpty()) {
            throw new IllegalArgumentException("输入的列表为空");
        }
        AtomicReference<RobotMapPos> nearestPos = new AtomicReference<>();
        String lastStation = robotDriverService.getWebPos().getLastStation();
        if (StrUtil.isNotEmpty(lastStation)) {
            robotMapPosList.stream().filter(t -> t.getCode().equals(lastStation)).findFirst().ifPresent(t -> {
                nearestPos.set(t);
            });
        }
        if (nearestPos.get() == null) {
            GeometryFactory geometryFactory = new GeometryFactory();

            double distance = Double.MAX_VALUE;
            boolean foundValidPosition = false;
            Point point = geometryFactory.createPoint(new Coordinate(x, y));

            for (RobotMapPos pos : robotMapPosList) {
                Point targetPos = geometryFactory.createPoint(new Coordinate(pos.getPosX(), pos.getPosY()));
                double currentDistance = DistanceOp.distance(point, targetPos);
                if (currentDistance < distance) {
                    distance = currentDistance;
                    nearestPos.set(pos);
                    foundValidPosition = true;
                }
            }

            if (!foundValidPosition) {
                throw new IllegalStateException("没有找到有效的点位，所有距离均超过阈值。");
            }
        }
        return nearestPos.get();
    }

}
